
#include "Win32ThreadHandle.h"
#include "SyncObject.h"

namespace common {

Win32Thread::Win32Thread() {
  // Bouml preserved body begin 0002D598
	mNativeThreadId = 0;
	mNativeHandle = NULL;
  // Bouml preserved body end 0002D598
}

Win32Thread::~Win32Thread() {
  // Bouml preserved body begin 0002D618
	Close();
  // Bouml preserved body end 0002D618
}

Win32Thread::Win32Thread(const Win32Thread & source) {
  // Bouml preserved body begin 0002D698
	mNativeThreadId = source.mNativeThreadId;
	mNativeHandle = NULL; // We'll open it later.	
  // Bouml preserved body end 0002D698
}

//Compares two thread handles
bool Win32Thread::operator==(const Thread * theOther) {
  // Bouml preserved body begin 000366AA
  // Bouml preserved body end 000366AA
}

//Returns object of current (calling) thread.
Error::code Win32Thread::Current() {
  // Bouml preserved body begin 00026B18
	Close();
	mNativeThreadId = ::GetCurrentThreadId();

	return Error::noError;
  // Bouml preserved body end 00026B18
}

//Resumes this thread, or reduces its suspension count.
Error::code Win32Thread::Resume() {
  // Bouml preserved body begin 00026898
	Prepare();

	if ( -1 == ::ResumeThread( mNativeHandle ) ) {
		return (Error::code)( ( (int)Error::systemError ) + ::GetLastError() );
	}

	return Error::noError;
  // Bouml preserved body end 00026898
}

//Suspends the thread, or increases its suspension counter.
Error::code Win32Thread::Suspend() {
  // Bouml preserved body begin 00026918
	Prepare();

	if ( -1 == ::SuspendThread( mNativeHandle ) ) {
		return (Error::code)( ( (int)Error::systemError ) + ::GetLastError() );
	}

	return Error::noError;
  // Bouml preserved body end 00026918
}

//Terminates Running thread. Should be used with causion.
Error::code Win32Thread::Terminate() {
  // Bouml preserved body begin 00026998
	Prepare();

	if ( !::TerminateThread( mNativeHandle, 0 ) ) {
		return (Error::code)( ( (int)Error::systemError ) + ::GetLastError() );
	}

	return Error::noError;
  // Bouml preserved body end 00026998
}

//Gives execution time, to another thread that is waiting.
//Error if no waiting threads.
Error::code Win32Thread::Switch() {
  // Bouml preserved body begin 00026B98
	if ( !::SwitchToThread() )
	{
		return Error::noWaitingThread;
	}
	return Error::noError;
  // Bouml preserved body end 00026B98
}

//Suspends current thread and yields for given time (in miliseconds)
Error::code Win32Thread::Sleep(unsigned long int sleepTime) {
  // Bouml preserved body begin 00026C18
	::Sleep( sleepTime );

	return Error::noError;
  // Bouml preserved body end 00026C18
}

//Standard wait for single sync object.
Error::code Win32Thread::WaitFor(unsigned int timeout) {
  // Bouml preserved body begin 0002DB98
	DWORD res = ::WaitForSingleObject( mNativeHandle, (DWORD)timeout );

	switch ( res ) {
		case WAIT_ABANDONED: {
			return Error::waitAbandoned;
		} break;
		case WAIT_OBJECT_0: {
			return Error::noError;
		} break;
		case WAIT_TIMEOUT: {
			return Error::waitTimeout;
		} break;
		case WAIT_FAILED:
		default: {
			return (Error::code)( ( (int)Error::systemError ) + GetLastError() );
		}
	}
  // Bouml preserved body end 0002DB98
}

//Waits for multiple sync objects.
Error::code Win32Thread::WaitForMultiple(unsigned int count, const SyncObject * handleList, bool waitAll, unsigned int milliseconds) {
  // Bouml preserved body begin 0002DC18
	DWORD * winHandles = new DWORD[ count + 1 ];

	GetHandle( winHandles[ 0 ] );
	for ( int i = 1; i < count; i++ ) {
		Win32SyncObject * obj = dynamic_cast<Win32SyncObject>(&handleList[ i - 1 ]);
		if ( obj != NULL ) {
			obj->GetHandle( winHandles[ i ] );
		} else {
			winHandle[ i ] = NULL;
		}
	}

	// will it work with some NULLs on the list ?
	DWORD res = ::WaitForMultipleObjects( count+1, winHandles, waitAll, milliseconds );

	switch

  // Bouml preserved body end 0002DC18
}

//Our own startup routine for new thread.
DWORD WINAPI Win32Thread::ThreadProc(LPVOID lpParameter)
{
  // Bouml preserved body begin 00031D2A
	ThreadStartRoutine * startRoutine = (ThreadStartRoutine*)lpParameter;
	return (DWORD)(*startRoutine)();
  // Bouml preserved body end 00031D2A
}

//To avoid exceptions during copying of these objects. Only Thread Ids are transfered.
//Later this method is responsible for preparing proper Handle to use.
void Win32Thread::Prepare() {
  // Bouml preserved body begin 000320AA
	if ( mNativeHandle == NULL && mNativeThreadId != 0 ) {
		mNativeHandle = OpenThread( NULL, false, mNativeThreadId );
	}
  // Bouml preserved body end 000320AA
}


} // namespace common
